﻿using Futaba.SBus.Extensions;
using Futaba.SBus.Telemetry;
using Futaba.SBus.Telemetry.Configuration;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Futaba.SBus.Configuration
{
	/// <summary>
	/// Creates <see cref="ModelConfiguration"/>
	/// </summary>
	public class ModelConfigurationFactory
	{

		#region Singleton

		private static ModelConfigurationFactory _singletonModelConfigurationFactory;
		private static readonly object ModelConfigurationFactorySingletonLock = new object();

		/// <summary>
		/// A singleton of this class
		/// </summary>
		public static ModelConfigurationFactory DefaultInstance
		{
			get
			{
				if (_singletonModelConfigurationFactory == null)
				{
					// ReSharper disable PossibleMultipleWriteAccessInDoubleCheckLocking
					lock (ModelConfigurationFactorySingletonLock)
					{
						if (_singletonModelConfigurationFactory == null)
							_singletonModelConfigurationFactory = new ModelConfigurationFactory();
					}
					// ReSharper restore PossibleMultipleWriteAccessInDoubleCheckLocking
				}
				return _singletonModelConfigurationFactory;
			}
		}

		#endregion

		/// <summary>
		/// Loads and returns the list of <see cref="Slot">slots</see> from the provided configuration file
		/// </summary>
		/// <param name="xmlConfiguration">the file to load the configuration from</param>
		/// <param name="knownSensors">Optional list of known sensors (default list is used, if none is provided)</param>
		/// <param name="slotFactory">Optional <see cref="SlotFactory"/> instance to be used to configure the loaded slots</param>
		/// <returns>Returns the <see cref="ModelConfiguration"/> restored from the provided stream</returns>
		/// <seealso cref="Save"/>
		public ModelConfiguration Load(Stream xmlConfiguration, Sensor[] knownSensors = null, SlotFactory slotFactory = null)
		{
			var config = xmlConfiguration.Load<ModelConfiguration>(null);
			var slots = config.Slots;
			if (slotFactory == null)
				slotFactory = SlotFactory.DefaultInstance;
			slotFactory.ConnectSlotToConfiguration(slots, knownSensors);
			return config;
		}

		/// <summary>
		/// Saves the supplied <paramref name="configuration"/> to the provided stream as XML
		/// </summary>
		/// <param name="configuration">the slots to save</param>
		/// <param name="outFile">the stream to write the XML to</param>
		/// <param name="encoding">the optional encoding to use for XML serialization.
		/// If not supplied, <see cref="Encoding.Default"/> is used instead</param>
		public void Save(ModelConfiguration configuration, Stream outFile, Encoding encoding = null)
		{
			configuration.ToXml(outFile, encoding ?? Encoding.Default, null);
		}

	}
}
